package com.fh.shop.api.interceptors;

import com.alibaba.fastjson.JSON;
import com.fh.shop.api.annotation.NeedLogin;
import com.fh.shop.api.common.Constant;
import com.fh.shop.api.common.ResponseEnum;
import com.fh.shop.api.exception.TokenException;
import com.fh.shop.api.member.vo.MemberVo;
import com.fh.shop.api.util.KeyUtil;
import com.fh.shop.api.util.Md5Util;
import com.fh.shop.api.util.RedisUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Base64;

public class LoginInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //解决不支持自定义注解的问题 允许客户端传递 自定义的头信息
        response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS,"x-auth,Content-Type");

        //解决不支持除了get,post请求外的其他请求
        response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS,"DELETE,PUT");

        //解决跨域问题
        response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN,"*");

        //解决options请求问题
        String requestMethod = request.getMethod();
        if (requestMethod.equalsIgnoreCase("options")){
            return false;
        }

        //判断请求头有没有实现HandlerMethod
        if (!(handler instanceof HandlerMethod)){
            //没有则说明是普通方法 直接放行
            return true;
        }

        //获取方法
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        //判断是否有注解
        if (!method.isAnnotationPresent(NeedLogin.class)){
            return true;
        }

        //获取请求头
        String header = request.getHeader("x-auth");

        //判断请求头的内容
        if (StringUtils.isEmpty(header)){
            throw new TokenException(ResponseEnum.TOKEN_IS_NULL);
        }

        //分割内容
        String[] tokenArr = header.split("\\.");

        //验证格式
        if (tokenArr.length != 2){
            throw new TokenException(ResponseEnum.TOKEN_FORMAT_ERROR);
        }

        //验签
        String base64MemberJson = tokenArr[0];
        String base64Sign = tokenArr[1];
        //base64解码
        String memberJson = null;
        String sign = null;
        try {
            memberJson = new String(Base64.getDecoder().decode(base64MemberJson));
            sign = new String(Base64.getDecoder().decode(base64Sign));
        } catch (Exception e) {
            e.printStackTrace();
            throw new TokenException(ResponseEnum.TOKEN_DECODING_ERROR);
        }
        //生成新的签名
        String newSign = Md5Util.sign(memberJson, Constant.SECRET);
        //判断是否被篡改
        if (!newSign.equals(sign)){
            throw new TokenException(ResponseEnum.TOKEN_SIGN_ERROR);
        }

        //过期时间
        //字符串转对象
        MemberVo memberVo = JSON.parseObject(memberJson, MemberVo.class);
        Long id = memberVo.getId();

        //验证uuid
        String uuid = memberVo.getUuid();
        String redisUUID = RedisUtil.get(KeyUtil.memberKey(id));
        if (!uuid.equals(redisUUID)){
            throw new TokenException(ResponseEnum.UUID_MISMATCH);
        }

        //判断键是否还存在
        String memberKey = KeyUtil.memberKey(id);
        if (!RedisUtil.exists(memberKey)){
            throw new TokenException(ResponseEnum.TOKEN_EXPIRED);
        }

        //重新设置过期时间 (续命)
        RedisUtil.expire(memberKey, Constant.MEMBER_EXPIRATION);

        //存入request中
        request.setAttribute(Constant.MEMBERVO,memberVo);
        return true;
    }
}
